use std::{ net::TcpStream, time::Duration, thread, error::Error, process::{self}, sync::mpsc::{Sender, Receiver, TryRecvError} };
use std::sync::mpsc::channel;

use crate::{channel::{cmd::{Data, self, Cmd}, http::{prelude::NrRes, self}, tcp::prelude::NrUReader, tcp::prelude::NrWriter}, cli::conf::ConfCli};

pub fn connect_server() {
    ConfCli::load_conf();
    let mut requestor = Requestor::init();
    requestor.send_conf();
    requestor.read_server();
}

pub struct Requestor {
    
    reader: Option<NrUReader>,

    writer: Option<NrWriter>,

}

impl Requestor {
    
    pub fn init() -> Self {
        let conf: ConfCli = ConfCli::get_conf();
        match connect(conf) {
            Some(stream) => {
                match NrUReader::from(&stream) {
                    Ok(reader) => {
                        Self { reader: Some(reader), writer: Some(NrWriter::from(&stream)) }
                    },
                    Err(_) => {
                        println!("Set unblocking stream fail!");
                        process::exit(1);
                    },
                }
            },
            None => {
                println!("Connect server fail!");
                process::exit(1);
            },
        }
    }

    /// 发送配置文件到服务器
    fn send_conf(&mut self) {
        self.loop_send(&Data::conf().to_vec()[..]);
    }

    /// 发送心跳包到服务器
    // fn send_heart(&mut self) {
    //     self.loop_send(&Data::heart().to_vec());
    // }

    fn loop_send(&mut self, bytes: &[u8]) {
        loop {
            let success = self.send_bytes(bytes);
            if success {
                break;
            } else {
                self.reconnect().unwrap();
            }
        }
    }

    fn send_bytes(&mut self, bytes: &[u8]) -> bool {
        match &mut self.writer {
            Some(writer) => {
                match writer.write(&bytes.to_vec()) {
                    Ok(_) => { true },
                    Err(_) => { 
                        println!("Lose server connect");
                        false 
                    },
                }
            },
            None => { 
                println!("Lose server connect");
                false
            },
        }
    }

    fn reconnect(&mut self) -> Result<(), Box<dyn Error>> {
        if self.reader.is_some() {
            return Ok(())
        }
        loop {
            match connect(ConfCli::get_conf()) {
                Some(stream) => {
                    self.reader = Some(NrUReader::from(&stream).unwrap());
                    self.writer  = Some(NrWriter::from(&stream));
                    self.send_conf();
                    break;
                },
                None => {
                    println!("Reconnect server fail!");
                    thread::sleep(Duration::from_secs(5));
                },
            }
        }
        Ok(())
    }

    fn read_server(&mut self) {
        let mut cli_bytes: Vec<u8> = vec![];
        let (sx, rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
        loop {
            match &mut self.reader {
                Some(reader) => {
                    match reader.read(&mut cli_bytes) {
                        Ok(size) => {
                            if size != 0 {
                                let (datas, residual_bytes) = cmd::get_datas(cli_bytes.clone());
                                cli_bytes = residual_bytes;
                                for data in datas {
                                    match data.cmd {
                                        Cmd::Proxy2Cli => {
                                            proxy_local(data, &sx);
                                        },
                                        _ => {}
                                    }
                                }
                            }
                        },
                        Err(_) => {
                            self.reader = None;
                            self.writer = None;
                            self.reconnect().unwrap();
                        },
                    }
                },
                None => {},
            }
            match rx.try_recv() {
                Ok(v) => {
                    self.loop_send(&v[..]);
                },
                Err(e) => { 
                    if e != TryRecvError::Empty {
                        println!("{:?}", e);
                    }
                },
            }
        }
    }

}

/// 断线重连
/// 获取到锁的任务才执行
/// 防止重复重连
fn connect(conf: ConfCli) -> Option<TcpStream> {
    println!("=====> 远程服务器地址 {}:{} ", conf.remote.host, conf.remote.port);
    println!("=====> 正在尝试连接 ");
    match TcpStream::connect((conf.remote.host, conf.remote.port)) {
        Ok(stream) => {
            println!("=====> 连接成功 ");
            Some(stream)
        },
        Err(_) => {
            None
        },
    }
}

fn proxy_local(data: Data, sx: &Sender<Vec<u8>>) {
    let sx_clone = sx.clone();
    thread::spawn(move || {
        let conf = ConfCli::get_conf();
        match TcpStream::connect((&conf.local.host[..], conf.local.port)) {
            Ok(stream) => {
                let mut writer = NrWriter::from(&stream);
                writer.write(&data.data).unwrap();
                let response = NrRes::read_from_stream(&mut NrUReader::from(&stream).unwrap()).unwrap();
                let res_bytes = Data::proxy_server(response.to_vec(), conf.id, data.pid).to_vec();
                sx_clone.send(res_bytes).unwrap();
            },
            Err(_) => {
                sx_clone.send(Data::proxy_server(http::prelude::status_500().as_bytes().to_vec(), conf.id, data.pid).to_vec()).unwrap();
            },
        }
    });
}